<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>贪吃蛇</title>
    <style>
        :root {
            --width: 300px;
        }
        #game-map {
            width: var(--width);
            height: 200px;
            border: 2px solid #ccc;
            box-sizing: border-box;
            position: relative;
            overflow: hidden;
        }
        .btns { 
            width: var(--width);
            text-align: center;
            margin-top: 20px;
        }
        .btns button {
            padding: 10px 15px;
        }
    </style>
</head>
<body>
    <div id="game-map"></div>
    <div class="btns">
        <p class="score">分数：0</p>
        <button class="btn">开始游戏</button>
    </div>
    <script>
        // 工具函数 获取随机数(min到max之间 不包含max)
        function getRandom(min,max){
            const minNum = Math.min(min,max);
            const maxNum = Math.max(min, max);
            return Math.floor(Math.random() * (maxNum-minNum)+minNum)
        }
        // 地图
        const map = document.getElementById("game-map");
        /**
         * 食物
         *   1、初始化食物（宽高颜色等）
         *   2、在地图上随机生成
         *   3、管理食物（删除）
         * 
         * */ 
        function Food(width, height, color){
            // 初始化属性
            this.width = width;
            this.height = height;
            this.color = color;
            this.x = 0;
            this.y = 0;
            // 保存食物
            this.els = []
        }

        // 生成食物
        Food.prototype.render = function(map){
            // 渲染之前移除之前的食物
            this.remove(map)

            // 地图的宽高
            let mapW = map.offsetWidth
            let mapH = map.offsetHeight
            // 食物随机出现范围 注意： 食物是绝对定位相对 根据地图进行定位的
            // 随机获取食物的位置  必须是宽高的倍数 
            this.x = getRandom(0, mapW/this.width)*this.width
            this.y = getRandom(0, mapH/this.height)*this.height
            // console.log(this.x, this.y, maxX, maxY)

            // 创建食物
            let div = document.createElement("div")
            div.style.width = this.width+"px"
            div.style.height = this.height+"px"
            div.style.position = "absolute"
            div.style.left = this.x+"px"
            div.style.top = this.y+"px"
            div.style.backgroundColor = this.color
            this.els.push(div)
            console.log("生成食物：", div)

            map.appendChild(div)
            
        }

        // 删除食物
        Food.prototype.remove = function(map){
            for(let i=0;i<this.els.length;i++){
                this.els[i]?.parentNode.removeChild(this.els[i])
                this.els.splice(i,1)
                i--;
            }
        }

        /*
        蛇
        目标功能点：

            初始化蛇（宽，高，颜色、长度等）
            在地图上初始定位
            蛇的移动与管理（吃一个食物生成一个新的蛇对象）
            判断是否吃到食物（蛇头的坐标与食物坐标重合
        
        */ 
       function Snake(width, height, direction,headColor, bodyColor,){
            //  存储蛇 div
            this.els = []
            this.width = width
            this.height = height
            this.direction = direction
            this.headColor = headColor
            this.bodyColor = bodyColor
            // 蛇身体 初始三节
            this.body = [
                {x: 3, y: 2, color: this.headColor },
                {x: 2, y: 2, color: this.bodyColor },
                {x: 1, y: 2, color: this.bodyColor }
            ]
            //分数
            this.score = 0
       }

    //    渲染
       Snake.prototype.render = function(map){
            // 删除之前创建的蛇
            this.remove()
            for(let i=0;i<this.body.length;i++){
                let obj = this.body[i]

                let div = document.createElement("div");
                div.style.width = this.width+"px"
                div.style.height = this.height+"px"
                div.style.position = "absolute"
                div.style.left = obj.x * this.width +"px"
                div.style.top = obj.y * this.height +"px"
                div.style.backgroundColor = obj.color
                div.className = "snake-"+(i+1)

                this.els.push(div)
                map.appendChild(div)

            }
       }

    //    移动
    Snake.prototype.move = function(food, map){
        // 控制蛇节的移动 (当前蛇节 移动到上一个蛇节)
        for(let i=this.body.length-1;i>0;i--){
            this.body[i].x = this.body[i-1].x;
            this.body[i].y = this.body[i-1].y
        }
        // console.log(this.body)
        // 蛇头
        let head = this.body[0]
        // 蛇的行走方向
        switch(this.direction){
            case "right":
                head.x+=1
                break;
            case "left":
                head.x-=1
                break;
            case "top": 
                head.y-=1
                break;
            case "bottom":
                head.y+=1
                break;
        }
        // 蛇吃食物
        // 判断蛇头的位置是否与食物的位置重合
        let headX = head.x*this.width;
        let headY = head.y*this.height;
        // console.log(food.x,food.y,headX, headY)
        if(headX == food.x && headY == food.y){
            let last = this.body[this.body.length-1];
            // 往身体里面再加一个蛇节
            this.body.push({
                x: last.x,
                y: last.y,
                color: last.color
            })
            // 分数
            this.score++
            updateScore(this.score)
            // 重新生成一个食物
            food.render(map)
        }
    }
    // 移除蛇
    Snake.prototype.remove = function(map){
        for(let i=0;i<this.els.length;i++){
            this.els[i]?.parentNode.removeChild(this.els[i])
            this.els.splice(i,1)
            i--
        }
    }

    // 游戏入口
    function Game(){
        // 创建蛇和食物
        this.food = new Food(10,10,"skyblue");
        // 初始化蛇
        this.snake = new Snake(10,10,"right","red","skyblue")
        this.map = map
        // 定时器
        this.timer = null
        // 游戏状态
        this.state = "static"
    }

    Game.prototype.start = function(){
        this.state = "start"
        // 渲染蛇和食物
        this.food.render(this.map)
        this.snake.render(this.map)
        this.run()
        this.dir()
    }

    // 让蛇动起来
    Game.prototype.run = function(){
        this.timer = setInterval(()=>{
            // 让蛇动起来
            this.snake.move(this.food, this.map)
            // 当蛇遇到边界游戏结束
            let minX = this.map.offsetLeft
            let maxX = this.map.offsetWidth
            let minY = this.map.offsetTop
            let maxY = this.map.offsetHeight
            let headEl = this.snake.els[0];
            let headMinX = headEl.offsetLeft
            let headMaxX = headEl.offsetLeft+headEl.offsetWidth
            let headMinY = headEl.offsetTop
            let headMaxY = headEl.offsetTop + headEl.offsetHeight

            if(headMinX < minX || headMaxX >maxX 
            || headMinY < minY || headMaxY > maxY){
                console.log(this.snake)
                console.log({headMinX,minX} )
                console.log({headMaxX,maxX} )
                console.log({headMinY,minY} )
                console.log({headMaxY,maxY} )
                clearInterval(this.timer)
                this.state = "finished"
                alert("游戏结束，您的总分数是："+this.snake.score+"分")
                return
            }
            // 根据新的body数据重新渲染 实现移动效果
            this.snake.render(this.map)

        }, 200)
    }

    // 控制方向
    Game.prototype.dir = function(){
        document.addEventListener("keydown", (e)=>{
            switch(e.code){
                case "ArrowUp":
                    this.snake.direction = "top";
                    break;
                case "ArrowDown":
                    this.snake.direction = "bottom";
                    break;
                case "ArrowLeft":
                    this.snake.direction = "left";
                    break;
                case "ArrowRight":
                    this.snake.direction = "right";
                    break;
            }
        })
    }

    // 更新分数
    let scoreP = document.querySelector(".score")
    function updateScore(score){
        scoreP.innerText = `分数：${score}`
    }

    // 实例化游戏

    // 开始游戏
    let start = document.querySelector(".btn")
    const game = new Game()
    start.addEventListener("click", function(){
        if( game.state == "static"){
            this.innerText = "重新开始"
            game.start()
        }else if(game.state == "finished") {
            console.log("重新开始")
        }
    })






    </script>
</body>
</html>